package cn.calm.swing.osgi.api.util;

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import cn.calm.swing.osgi.api.annotation.Required;
import cn.calm.swing.osgi.api.entity.Project;
import cn.calm.swing.osgi.api.entity.ProjectProperty;
import cn.calm.swing.osgi.api.exception.SwingException;

public class EntityUtil {
	static Set<Class<?>> types = new HashSet<Class<?>>();
	static {
		types.add(String.class);
		types.add(Integer.class);
		types.add(Boolean.class);
	}

	public static void entityToMap(Project project, Object o, String spx) {
		Class<?> clazz = o.getClass();
		Field[] declaredFields = clazz.getDeclaredFields();
		for (Field f : declaredFields) {
			Class<?> type = f.getType();
			if (types.contains(type)) {
				f.setAccessible(true);
				try {
					Object val = f.get(o);
					if (val == null) {
						continue;
					}
					project.addProperties(new ProjectProperty(spx, f.getName(),
							String.valueOf(val)));
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static <E> E projectToEntity(Project project, Class<E> clazz,
			String spx) {
		E entity = null;
		try {
			entity = clazz.newInstance();
			List<ProjectProperty> properties = project.getProperties();
			for (ProjectProperty pp : properties) {
				String key = pp.getKey();
				if (key.equals(spx)) {
					entity = processEntity(clazz, entity, pp);
				}
			}
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return entity;
	}

	private static <E> E processEntity(Class<E> clazz, E entity,
			ProjectProperty pp) throws IllegalAccessException {
		try {
			Field field = clazz.getDeclaredField(pp.getProperty());
			Class<?> type = field.getType();
			field.setAccessible(true);
			Object o = valueOf(type, pp.getPropertyValue());
			field.set(entity, o);
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		}
		return entity;
	}

	public static <E> List<E> projectToListEntity(Project project,
			Class<E> clazz, String spx) {
		List<E> list = new ArrayList<E>();

		List<ProjectProperty> properties = project.getProperties();
		for (ProjectProperty pp : properties) {
			if (pp.getKey().startsWith(spx)) {
				String key = pp.getKey();
				int index = spx.length() + 1;
				int i = Integer.valueOf(key.substring(index, key.length() - 1));
				E entity = null;
				try {
					entity = list.get(i);
				} catch (Exception e) {
					try {
						entity = clazz.newInstance();
						list.add(i, entity);
					} catch (InstantiationException e1) {
						e1.printStackTrace();
					} catch (IllegalAccessException e1) {
						e1.printStackTrace();
					}
				}
				try {
					entity = processEntity(clazz, entity, pp);
					list.set(i, entity);
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
		return list;
	}

	public static Object valueOf(Class<?> clazz, String val) {
		if (clazz == Integer.class) {
			return Integer.valueOf(val);
		} else if (clazz == String.class) {
			return val;
		} else if (clazz == Boolean.class) {
			return Boolean.valueOf(val);
		}
		return null;
	}

	public static void validate(Object o) throws SwingException {
		Class<?> clazz = o.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field f : fields) {
			Required an = f.getAnnotation(Required.class);
			if (an != null) {
				f.setAccessible(true);
				try {
					Object object = f.get(o);
					if (object == null) {
						throw new SwingException(an.message());
					} else if (object instanceof String) {
						if ("".equals(((String) object).trim())) {
							throw new SwingException(an.message());
						}
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				}
			}
		}
	}

	public static void popetyCopy(Object source, Object target) {
		Class<? extends Object> clazz = source.getClass();
		Field[] fields = clazz.getDeclaredFields();
		for (Field f : fields) {
			if ((f.getModifiers() & Modifier.STATIC) == Modifier.STATIC) {
				continue;
			}
			if ((f.getModifiers() & Modifier.FINAL) == Modifier.FINAL) {
				continue;
			}
			f.setAccessible(true);
			try {
				PropertyDescriptor pd = new PropertyDescriptor(f.getName(),
						clazz);
				Method writeMethod = pd.getWriteMethod();
				Object value = f.get(source);
				writeMethod.invoke(target, value);
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IntrospectionException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
	}
}
